//
// Created by limo on 2025/9/27.
//

#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <functional>

#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>

namespace net {

    namespace asio = boost::asio;
    using boost::asio::ip::udp;

    // 消息接收回调：void(const std::string&, std::size_t)
    using ReceiveCallback = std::function<void(const std::string&, std::size_t)>;

    class UdpClient {
    public:
        // 构造函数：解析服务器地址和端口
        UdpClient(asio::io_context& ioContext, const std::string& serverAddress, short serverPort)
        // 客户端通常不需要绑定特定的本地端口，让系统自动分配即可
                : m_socket(ioContext, udp::endpoint(udp::v4(), 0)),
                  m_ioContext(ioContext)
        {
            // 1. 使用 resolver 解析服务器地址
            udp::resolver resolver(ioContext);

            try {
                // 解析服务器的端点信息
                // 注意：这里使用同步解析，因为只在初始化时执行一次
                udp::resolver::results_type endpoints = resolver.resolve(udp::v4(), serverAddress, std::to_string(serverPort));

                // 假设第一个结果就是目标服务器
                m_remoteEndpoint = *endpoints.begin();

                std::cout << "UdpClient initialized. Target: " << m_remoteEndpoint.address().to_string()
                          << ":" << m_remoteEndpoint.port() << std::endl;

                // 2. 启动异步接收循环，准备接收服务器的响应
                startReceive();

            } catch (const boost::system::system_error& e) {
                std::cerr << "Resolver Error: " << e.what() << std::endl;
                // 客户端如果无法解析地址，则无法工作
                throw;
            }
        }

        // --- 公有方法：设置回调函数 ---

        void setReceiveCallback(ReceiveCallback cb) {
            m_onReceive = std::move(cb);
        }

        // --- 公有方法：发送消息 ---

        void sendMessage(const std::string& message) {
            // 使用 shared_ptr 保证数据在异步发送完成前保持有效
            auto sharedMessage = std::make_shared<std::string>(message);

            m_socket.async_send_to(
                    asio::buffer(*sharedMessage),
                    m_remoteEndpoint,
                    boost::bind(&UdpClient::handleSend, this,
                                sharedMessage,
                                asio::placeholders::error,
                                asio::placeholders::bytes_transferred)
            );
        }

    private:
        // 成员变量
        udp::socket m_socket;
        udp::endpoint m_remoteEndpoint;
        std::array<char, 1024> m_recvBuffer;
        asio::io_context& m_ioContext;

        // 回调成员变量
        ReceiveCallback m_onReceive;

        // --- 异步接收逻辑 ---
        void startReceive() {
            m_socket.async_receive_from(
                    asio::buffer(m_recvBuffer),
                    // 注意：接收时仍需提供一个 endpoint 来接收服务器的地址，即使我们知道它
                    m_remoteEndpoint,
                    boost::bind(&UdpClient::handleReceive, this,
                                asio::placeholders::error,
                                asio::placeholders::bytes_transferred)
            );
        }

        void handleReceive(const boost::system::error_code& error, std::size_t bytesTransferred) {
            if (!error) {
                // 1. 提取消息并触发回调
                std::string receivedMessage(m_recvBuffer.data(), bytesTransferred);
                if (m_onReceive) {
                    m_onReceive(receivedMessage, bytesTransferred);
                }

                // 2. 再次启动接收，继续等待下一个响应
                startReceive();

            } else if (error != asio::error::operation_aborted) {
                // 发生错误，且不是操作被取消（如 io_context 停止）
                std::cerr << "[ERROR] Receive error: " << error.message() << std::endl;
                // 可以选择重新启动接收或停止
                startReceive();
            }
        }

        // --- 异步发送回调 ---
        void handleSend(std::shared_ptr<std::string> /*message*/,
                        const boost::system::error_code& error,
                        std::size_t /*bytesTransferred*/) {
            if (error) {
                std::cerr << "[ERROR] Send error: " << error.message() << std::endl;
            }
            // sharedMessage 在这里自动释放
        }
    };

} // net
